import { Types, defineComponent, addComponent, removeComponent, removeEntity, type IWorld, type Entity } from './ecs';
import { log } from './log';
import { describe } from '$lib';
import { Clock } from './clock';
import { registerAction } from './actions';
import { registerCorpseDrop } from './death';
import { getPos3, hasPos3, placeOnMap, removeFromMap } from './pos3';
import { logVisible } from './render3';

const MAX_INVENTORY = 64;

export const Inventory = defineComponent('Inventory', {
  size: Types.ui32,
  count: Types.ui32,
  inv: [Types.eid, MAX_INVENTORY],
});

export const Stored = defineComponent('Stored', {
  parent: Types.eid,
});

export const getInventory = (world: IWorld, char: Entity) => {
  const sz = Inventory.count[char];
  let res = [];
  for (let i = 0; i < sz; ++i) {
    res.push(Inventory.inv[char][i]);
  };
  return res;
};

export const PickupAction = (item) => (world, e) => {
  let error = false;
  const epos = getPos3(e);
  const ipos = getPos3(item);
  if (epos.x !== ipos.x || epos.y !== ipos.y) {
    error = "Cannot pick up remotely";
  }
  return {
    error,
    action: () => {
      Clock.time[e] += 5; // TODO
      const n = Inventory.count[e];
      if (n >= Inventory.size[e]) {
        log(`${describe(world, e)}'s inventory is full`);
        return;
      }
      Inventory.inv[e][n] = item;
      ++Inventory.count[e];
      removeFromMap(world, item);
      addComponent(world, Stored, item);
      Stored.parent[item] = e;
      logVisible(e, `${describe(world, e)} picks up ${describe(world, item)}`);
    },
  };
};

export const DropAction = (item) => (world, e) => {
  return {
    error: false,
    action: () => {
      Clock.time[e] += 5; // TODO
      // TODO: check equipped?
      const res = removeFromInventory(world, e, item);
      if (!res) {
        log('DROPPING ITEM NOT IN INVENTORY!');
        return;
      }
      const { x, y, z } = getPos3(e);
      placeOnMap(world, item, x, y, z);
      logVisible(e, `${describe(world, e)} drops ${describe(world, item)}`);
    },
  };
};

registerAction([Stored], 'drop', DropAction);

export const addToInventory = (world, e, item) => {
  const ix = Inventory.count[e];
  if (ix >= Inventory.size[e]) {
    return false;
  }
  Inventory.inv[e][ix] = item;
  ++Inventory.count[e];
  return true;
};

export const removeFromInventory = (world, e, item) => {
  const ix = Inventory.inv[e].indexOf(item);
  if (ix < 0) {
    return false;
  }
  --Inventory.count[e];
  for (let i = ix; i < Inventory.count[e]; ++i) {
    Inventory.inv[e][i] = Inventory.inv[e][i+1];
  }
  Inventory.inv[e][Inventory.count[e]] = 0;
  removeComponent(world, Stored, item);
  return true;
};

/// Remove all items from inventory and delete them
export const purgeInventory = (world, e) => {
  for (let item of getInventory(world, e)) {
    removeEntity(world, item);
  }
  Inventory.count[e] = 0;
};

registerCorpseDrop({
  target: Inventory,
  drop: (world, e) => {
    // TODO: configurable pos component
    if (hasPos3(world, e)) {
      const {x, y, z} = getPos3(e);
      for (let item of getInventory(world, e)) {
        placeOnMap(world, item, x, y, z);
      }
    } else {
      console.warn("Dead creature had inventory, but no Pos3, inventory items lost");
    }
  },
});
